package net.jcip.examples;

import java.util.*;

/**
 * Animals
 * <p/>
 * Thread confinement of local primitive and reference variables
 *
 * @author Brian Goetz and Tim Peierls
 */
public class Animals {
    /**
	 * @uml.property  name="ark"
	 * @uml.associationEnd  readOnly="true" inverse="this$0:net.jcip.examples.Animals$Ark"
	 */
    Ark ark;
    /**
	 * @uml.property  name="species"
	 * @uml.associationEnd  readOnly="true"
	 */
    Species species;
    /**
	 * @uml.property  name="gender"
	 * @uml.associationEnd  readOnly="true"
	 */
    Gender gender;

    public int loadTheArk(Collection<Animal> candidates) {
        SortedSet<Animal> animals;
        int numPairs = 0;
        Animal candidate = null;

        // animals confined to method, don't let them escape!
        animals = new TreeSet<Animal>(new SpeciesGenderComparator());
        animals.addAll(candidates);
        for (Animal a : animals) {
            if (candidate == null || !candidate.isPotentialMate(a))
                candidate = a;
            else {
                ark.load(new AnimalPair(candidate, a));
                ++numPairs;
                candidate = null;
            }
        }
        return numPairs;
    }


    /**
	 * @author  Administrator
	 */
    class Animal {
        /**
		 * @uml.property  name="species"
		 * @uml.associationEnd  
		 */
        Species species;
        /**
		 * @uml.property  name="gender"
		 * @uml.associationEnd  
		 */
        Gender gender;

        public boolean isPotentialMate(Animal other) {
            return species == other.species && gender != other.gender;
        }
    }

    /**
	 * @author   Administrator
	 */
    enum Species {
        /**
		 * @uml.property  name="aARDVARK"
		 * @uml.associationEnd  
		 */
        AARDVARK, /**
		 * @uml.property  name="bENGAL_TIGER"
		 * @uml.associationEnd  
		 */
        BENGAL_TIGER, /**
		 * @uml.property  name="cARIBOU"
		 * @uml.associationEnd  
		 */
        CARIBOU, /**
		 * @uml.property  name="dINGO"
		 * @uml.associationEnd  
		 */
        DINGO, /**
		 * @uml.property  name="eLEPHANT"
		 * @uml.associationEnd  
		 */
        ELEPHANT, /**
		 * @uml.property  name="fROG"
		 * @uml.associationEnd  
		 */
        FROG, /**
		 * @uml.property  name="gNU"
		 * @uml.associationEnd  
		 */
        GNU, /**
		 * @uml.property  name="hYENA"
		 * @uml.associationEnd  
		 */
        HYENA,
        /**
		 * @uml.property  name="iGUANA"
		 * @uml.associationEnd  
		 */
        IGUANA, /**
		 * @uml.property  name="jAGUAR"
		 * @uml.associationEnd  
		 */
        JAGUAR, /**
		 * @uml.property  name="kIWI"
		 * @uml.associationEnd  
		 */
        KIWI, /**
		 * @uml.property  name="lEOPARD"
		 * @uml.associationEnd  
		 */
        LEOPARD, /**
		 * @uml.property  name="mASTADON"
		 * @uml.associationEnd  
		 */
        MASTADON, /**
		 * @uml.property  name="nEWT"
		 * @uml.associationEnd  
		 */
        NEWT, /**
		 * @uml.property  name="oCTOPUS"
		 * @uml.associationEnd  
		 */
        OCTOPUS,
        /**
		 * @uml.property  name="pIRANHA"
		 * @uml.associationEnd  
		 */
        PIRANHA, /**
		 * @uml.property  name="qUETZAL"
		 * @uml.associationEnd  
		 */
        QUETZAL, /**
		 * @uml.property  name="rHINOCEROS"
		 * @uml.associationEnd  
		 */
        RHINOCEROS, /**
		 * @uml.property  name="sALAMANDER"
		 * @uml.associationEnd  
		 */
        SALAMANDER, /**
		 * @uml.property  name="tHREE_TOED_SLOTH"
		 * @uml.associationEnd  
		 */
        THREE_TOED_SLOTH,
        /**
		 * @uml.property  name="uNICORN"
		 * @uml.associationEnd  
		 */
        UNICORN, /**
		 * @uml.property  name="vIPER"
		 * @uml.associationEnd  
		 */
        VIPER, /**
		 * @uml.property  name="wEREWOLF"
		 * @uml.associationEnd  
		 */
        WEREWOLF, /**
		 * @uml.property  name="xANTHUS_HUMMINBIRD"
		 * @uml.associationEnd  
		 */
        XANTHUS_HUMMINBIRD, /**
		 * @uml.property  name="yAK"
		 * @uml.associationEnd  
		 */
        YAK, /**
		 * @uml.property  name="zEBRA"
		 * @uml.associationEnd  
		 */
        ZEBRA
    }

    /**
	 * @author   Administrator
	 */
    enum Gender {
        /**
		 * @uml.property  name="mALE"
		 * @uml.associationEnd  
		 */
        MALE, /**
		 * @uml.property  name="fEMALE"
		 * @uml.associationEnd  
		 */
        FEMALE
    }

    /**
	 * @author  Administrator
	 */
    class AnimalPair {
        /**
		 * @uml.property  name="one"
		 * @uml.associationEnd  
		 */
        private final Animal one;
		/**
		 * @uml.property  name="two"
		 * @uml.associationEnd  
		 */
		private final Animal two;

        public AnimalPair(Animal one, Animal two) {
            this.one = one;
            this.two = two;
        }
    }

    class SpeciesGenderComparator implements Comparator<Animal> {
        public int compare(Animal one, Animal two) {
            int speciesCompare = one.species.compareTo(two.species);
            return (speciesCompare != 0)
                    ? speciesCompare
                    : one.gender.compareTo(two.gender);
        }
    }

    class Ark {
        private final Set<AnimalPair> loadedAnimals = new HashSet<AnimalPair>();

        public void load(AnimalPair pair) {
            loadedAnimals.add(pair);
        }
    }
}


